package com.learning.datastruct.collection.list;

/**
 * @author ZLH
 */
public class MyArrayList<E> extends MyAbstractList<E> implements com.learning.datastruct.collection.list.MyList<E> {
    private Object[] elements;

    private static final int DEFAULT_CAPACITY = 10;

    public MyArrayList(int initialCapacity) {
        if (initialCapacity < 0) {
            throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
        } else {
            this.elements = new Object[Math.max(initialCapacity, DEFAULT_CAPACITY)];
        }
    }

    public MyArrayList() {
        this.elements = new Object[DEFAULT_CAPACITY];
    }



    @Override
    public void clear() {
        for (int i = 0; i < size; i++) {
            elements[i] = null;
        }
        size = 0;
    }

    @Override
    public E get(int index) {
        rangeCheck(index);
        return getElement(index);
    }

    @Override
    public E set(int index, E element) {
        rangeCheck(index);
        E old = getElement(index);
        elements[index] = element;
        return old;
    }

    @Override
    public void add(int index, E element) {
        rangeCheckForAdd(index);
        ensureCapacity(size + 1);
        // for (int i = size;i>index;i--) elements[i] = elements[i-1];
        System.arraycopy(elements, index, elements, index + 1,
                size - index);
        elements[index] = element;
        size++;
    }

    @Override
    public E remove(int index) {
        rangeCheck(index);
        E old = getElement(index);
        // for (int i = index; i < size - 1; i++) elements[i] = elements[i+1];
        if (size - 1 - index >= 0) {
            System.arraycopy(elements, index + 1, elements, index, size - 1 - index);
        }
        elements[--size] = null;
        return old;
    }

    @Override
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++) {
                if (elements[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = 0; i < size; i++) {
                if (o.equals(elements[i])) {
                    return i;
                }
            }
        }
        return NOTFOUND_INDEX;
    }

    @Override
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size - 1; i >= 0; i--) {
                if (elements[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = size - 1; i >= 0; i--) {
                if (o.equals(elements[i])) {
                    return i;
                }
            }
        }
        return NOTFOUND_INDEX;
    }

    @SuppressWarnings("unchecked")
    private E getElement(int index) {
        return (E) elements[index];
    }



    private void ensureCapacity(int capacity) {
        if (capacity > size) {
            int newCapacity = size + size >> 1;
            Object[] newElements = new Object[newCapacity];
            // for (int i = 0; i < size; i++) newElements[i] = elements[i];
            System.arraycopy(elements, 0, newElements, 0, size);
            elements = newElements;
        }
    }
}
